#include <iostream>
#include <windows.h>
#include <conio.h>
#include <vector>
#include <ctime>
#include <fstream>
#include <string>
#include <cstdlib>
#include <algorithm>

using namespace std;

// 游戏常量定义
const int WIDTH = 60;
const int HEIGHT = 20;
const int INIT_LENGTH = 4;
const int SLEEP_TIME = 200;

// 方向枚举
enum Direction { UP, DOWN, LEFT, RIGHT };

// 游戏全局变量
int score = 0;
int highScore = 0;
int sleeptime = SLEEP_TIME;
bool gameOver = false;
Direction dir = RIGHT;

// 蛇和食物结构
struct Point {
    int x, y;
    Point(int _x, int _y) : x(_x), y(_y) {}
};

vector<Point> snake;
Point food(0, 0);

// 函数声明
void printSnake();
void welcomeToGame();
void createMap();
void scoreAndTips();
void fileOut();
void fileIn();
void initSnake();
void createFood();
bool biteSelf();
bool hitWall();
void speedUp();
void speedDown();
void snakeMove();
void keyboardControl();
void gameOverScreen();
void explanation();
void gotoxy(int x, int y);
void setColor(int color);

// 主函数
int main() {
    system("title 贪吃蛇游戏");
    // 禁用输入缓冲，使按键即时响应
    system("mode con: lines=30 cols=80");
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
    DWORD mode;
    GetConsoleMode(hStdin, &mode);
    SetConsoleMode(hStdin, mode & ~ENABLE_LINE_INPUT);
    
    welcomeToGame();
    return 0;
}

// 设置控制台光标位置
void gotoxy(int x, int y) {
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 设置控制台文字颜色
void setColor(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

// 打印蛇的字符画
void printSnake() {
    setColor(10); // 绿色
    cout << "        _____         ____         _____" << endl;
    cout << "       /     \\       /    \\       /     \\" << endl;
    cout << "      /  ^ ^  \\_____/  o  \\_____/  ^ ^  \\" << endl;
    cout << "      \\  \\_/  /     \\_____/     \\  \\_/  /" << endl;
    cout << "       \\____ /                     \\____ /" << endl;
    setColor(7); // 恢复默认颜色
}

// 欢迎界面
void welcomeToGame() {
    system("cls");
    printSnake();
    
    setColor(14); // 黄色
    cout << "\n\n\t欢迎来到贪吃蛇游戏!" << endl;
    setColor(7);
    cout << "\n\t1. 开始游戏" << endl;
    cout << "\t2. 游戏说明" << endl;
    cout << "\t3. 查看最高分" << endl;
    cout << "\t4. 退出游戏" << endl;
    cout << "\n\t请选择(1-4): ";
    
    char choice;
    cin >> choice;
    
    switch(choice) {
        case '1':
            fileOut(); // 读取最高分
            initSnake();
            createMap();
            createFood();
            scoreAndTips();
            while (!gameOver) {
                if (_kbhit()) {
                    keyboardControl();
                }
                snakeMove();
                Sleep(sleeptime);
            }
            gameOverScreen();
            break;
        case '2':
            explanation();
            break;
        case '3':
            fileOut();
            system("cls");
            cout << "\n\t最高分: " << highScore << endl;
            cout << "\n\t按任意键返回...";
            _getch();
            welcomeToGame();
            break;
        case '4':
            exit(0);
        default:
            cout << "\n\t无效选择，请重新输入!" << endl;
            Sleep(1000);
            welcomeToGame();
    }
}

// 创建游戏地图
void createMap() {
    system("cls");
    setColor(3); // 青色
    
    // 绘制上下边界
    for (int i = 0; i < WIDTH; i += 2) {
        gotoxy(i, 0);
        cout << "■";
        gotoxy(i, HEIGHT - 1);
        cout << "■";
    }
    
    // 绘制左右边界
    for (int i = 1; i < HEIGHT - 1; i++) {
        gotoxy(0, i);
        cout << "■";
        gotoxy(WIDTH - 2, i);
        cout << "■";
    }
}

// 显示得分和提示
void scoreAndTips() {
    setColor(7);
    gotoxy(WIDTH + 5, 5);
    cout << "当前得分: " << score;
    gotoxy(WIDTH + 5, 7);
    cout << "最高得分: " << highScore;
    gotoxy(WIDTH + 5, 10);
    cout << "操作说明:";
    gotoxy(WIDTH + 5, 11);
    cout << "方向键控制移动";
    gotoxy(WIDTH + 5, 12);
    cout << "F1: 加速";
    gotoxy(WIDTH + 5, 13);
    cout << "F2: 减速";
    gotoxy(WIDTH + 5, 14);
    cout << "ESC: 退出游戏";
}

// 从文件读取最高分
void fileOut() {
    ifstream inFile("save.txt");
    if (inFile) {
        inFile >> highScore;
        inFile.close();
    } else {
        highScore = 0;
    }
}

// 写入最高分到文件
void fileIn() {
    ofstream outFile("save.txt");
    if (outFile) {
        outFile << highScore;
        outFile.close();
    }
}

// 初始化蛇
void initSnake() {
    snake.clear();
    // 初始化蛇身
    for (int i = 0; i < INIT_LENGTH; i++) {
        snake.push_back(Point(24 - i * 2, 5));
    }
    dir = RIGHT;
    score = 0;
    sleeptime = SLEEP_TIME;
    gameOver = false;
}

// 创建食物
void createFood() {
    srand(time(NULL));
    bool onSnake;
    
    do {
        onSnake = false;
        // 确保食物出现在网格内且不与蛇身重合
        food.x = (rand() % (WIDTH / 2 - 2) + 1) * 2;
        food.y = rand() % (HEIGHT - 2) + 1;
        
        for (const auto& segment : snake) {
            if (segment.x == food.x && segment.y == food.y) {
                onSnake = true;
                break;
            }
        }
    } while (onSnake);
    
    setColor(12); // 红色
    gotoxy(food.x, food.y);
    cout << "★";
}

// 判断是否咬到自己
bool biteSelf() {
    for (size_t i = 1; i < snake.size(); i++) {
        if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
            return true;
        }
    }
    return false;
}

// 判断是否撞墙
bool hitWall() {
    return (snake[0].x <= 0 || snake[0].x >= WIDTH - 2 || 
            snake[0].y <= 0 || snake[0].y >= HEIGHT - 1);
}

// 加速
void speedUp() {
    if (sleeptime > 50) {
        sleeptime -= 30;
        score += 2;
    }
}

// 减速
void speedDown() {
    if (sleeptime < 350) {
        sleeptime += 30;
        score = max(1, score - 2);
    }
}

// 蛇移动
void snakeMove() {
    // 保存蛇尾位置
    Point tail = snake.back();
    snake.pop_back();
    
    // 计算新蛇头位置
    Point newHead = snake[0];
    switch (dir) {
        case UP:
            newHead.y--;
            break;
        case DOWN:
            newHead.y++;
            break;
        case LEFT:
            newHead.x -= 2;
            break;
        case RIGHT:
            newHead.x += 2;
            break;
    }
    
    // 插入新蛇头
    snake.insert(snake.begin(), newHead);
    
    // 检查是否吃到食物
    if (newHead.x == food.x && newHead.y == food.y) {
        // 增加蛇身
        snake.push_back(tail);
        // 增加分数
        score++;
        // 创建新食物
        createFood();
        // 更新得分显示
        scoreAndTips();
    }
    
    // 检查游戏结束条件
    if (biteSelf() || hitWall()) {
        gameOver = true;
        return;
    }
    
    // 绘制蛇
    setColor(14); // 黄色
    gotoxy(newHead.x, newHead.y);
    cout << "●";
    
    // 清除旧蛇尾
    gotoxy(tail.x, tail.y);
    cout << "  ";
    
    // 绘制蛇身
    for (size_t i = 1; i < snake.size(); i++) {
        gotoxy(snake[i].x, snake[i].y);
        cout << "○";
    }
}

// 键盘控制
void keyboardControl() {
    int key = _getch();
    if (key == 0 || key == 224) {  // 处理方向键
        switch (_getch()) {
            case 72: if (dir != DOWN) dir = UP;    break; // ↑
            case 80: if (dir != UP) dir = DOWN;    break; // ↓
            case 75: if (dir != RIGHT) dir = LEFT; break; // ←
            case 77: if (dir != LEFT) dir = RIGHT; break; // →
        }
    }
    else {  // 处理其他键
        switch (key) {
            case 27: gameOver = true; break; // ESC
            case 59: speedUp();   break;    // F1
            case 60: speedDown(); break;    // F2
        }
    }
    scoreAndTips(); // 更新得分显示
}

// 游戏结束界面
void gameOverScreen() {
    system("cls");
    setColor(12); // 红色
    
    cout << "\n\n\t游戏结束!" << endl;
    cout << "\t你的得分: " << score << endl;
    
    if (score > highScore) {
        highScore = score;
        fileIn(); // 保存新纪录
        cout << "\t创纪录啦！最高分被你刷新啦，真棒！！！" << endl;
    } else {
        cout << "\t继续努力吧~你离最高分还差: " << highScore - score << " 分" << endl;
    }
    
    setColor(7);
    cout << "\n\t1. 重新开始" << endl;
    cout << "\t2. 退出游戏" << endl;
    cout << "\n\t请选择(1-2): ";
    
    char choice;
    cin >> choice;
    
    switch(choice) {
        case '1':
            welcomeToGame();
            break;
        case '2':
            exit(0);
        default:
            cout << "\n\t无效选择，将返回主菜单!" << endl;
            Sleep(1000);
            welcomeToGame();
    }
}

// 游戏说明界面
void explanation() {
    system("cls");
    setColor(11); // 浅蓝色
    
    cout << "\n\n\t游戏说明:" << endl;
    cout << "\t1. 使用方向键控制蛇的移动方向" << endl;
    cout << "\t2. 吃到食物(★)可以增加蛇的长度和得分" << endl;
    cout << "\t3. 按F1可以加速，按F2可以减速" << endl;
    cout << "\t4. 撞到墙壁或自己的身体游戏结束" << endl;
    cout << "\t5. 按ESC键可以随时退出游戏" << endl;
    
    setColor(7);
    cout << "\n\t按任意键返回主菜单...";
    _getch();
    welcomeToGame();
}
